package com.kc.gb.device.tools;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
public class DeviceCodeTool {

    private static String DEVICE_CODE = null;
    private static final String REPLACE = "-";

    public static void main(String[] args) throws SocketException {
        String deviceCode = generateDeviceCode();
        // 2f9d9aee27d39880ff547e94d4d50756e2679d8f202f7f16786154be0d5957ff
        log.info("deviceCode:{}", deviceCode);
    }

    public synchronized static String  getDeviceCode() throws SocketException {
        if(StringUtils.isEmpty(DEVICE_CODE)){
            DEVICE_CODE = generateDeviceCode();
        }
        return DEVICE_CODE;
    }

    /**
     * Init.
     *
     * @return
     */
    public static Map<String, List<String>> init() throws SocketException {
        Map<String, List<String>> macWithIp = new HashMap<>();
        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();
            if (Objects.nonNull(networkInterface)) {
                if (networkInterface.isVirtual() || networkInterface.isLoopback() || !networkInterface.isUp()) {
                    continue;
                }
                List<InterfaceAddress> interfaceAddresses = networkInterface.getInterfaceAddresses();
                List<String> ips = generateIps(networkInterface, interfaceAddresses);
                byte[] hardwareAddress;
                hardwareAddress = networkInterface.getHardwareAddress();
                String macAddress = generateMacAddress(hardwareAddress);
                if (StringUtils.isNotEmpty(macAddress) && CollectionUtils.isNotEmpty(ips)) {
                    macWithIp.put(macAddress, ips);
                }
            }
        }
        return macWithIp;
    }

    private static List<String> generateIps(NetworkInterface networkInterface, List<InterfaceAddress> interfaceAddresses) {
        List<String> ips = new ArrayList<>();
        for (InterfaceAddress interfaceAddress : interfaceAddresses) {
            InetAddress address = interfaceAddress.getAddress();
            String hostAddress = address.getHostAddress();
            if (StringUtils.isNotBlank(hostAddress) && isIp(hostAddress) && !address.isLoopbackAddress()
                    && address.isSiteLocalAddress() && !networkInterface.isVirtual()) {
                ips.add(hostAddress);
            }
        }
        return ips;
    }

    private static final String rexp =
            "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
    public static boolean isIp(String addr) {
        if (addr.length() < 7 || addr.length() > 15 || "".equals(addr)) {
            return false;
        }
        Pattern pat = Pattern.compile(rexp);
        Matcher mat = pat.matcher(addr);
        return mat.find();
    }

    /**
     * 生成mac地址
     */
    private static String generateMacAddress(byte[] hardwareAddress) {
        StringBuffer sb = new StringBuffer();
        if (Objects.nonNull(hardwareAddress)) {
            sb.setLength(0);
            for (int i = 0; i < hardwareAddress.length; i++) {
                if (i != 0) {
                    sb.append(REPLACE);
                }
                int temp = hardwareAddress[i] & 0xff;
                String str = Integer.toHexString(temp);
                if (str.length() == 1) {
                    sb.append("0" + str);
                } else {
                    sb.append(str);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 生成设备管理code
     */
    public static String generateDeviceCode() throws SocketException {
        Map<String, List<String>> macWithIp = init();
        DEVICE_CODE = macWithIp.keySet().stream().map(key -> key.replaceAll(REPLACE, "")).collect(Collectors.joining());
        log.info("generateDeviceCode:{}", DEVICE_CODE);
        return DEVICE_CODE;
    }
}
